package sqlo

import (
	"database/sql"
	"errors"
	"reflect"
	"strings"

	"github.com/jmoiron/sqlx"
)

// GetSingleRecord 通用单条记录查询方法
// dest: 指向目标结构体的指针
// db: 数据库连接
// query: SQL查询语句
// args: 查询参数
func GetSingleRecord(db *sqlx.DB, dest interface{}, query string, args ...interface{}) error {
	// 验证dest必须是指针
	if reflect.ValueOf(dest).Kind() != reflect.Ptr {
		return errors.New("dest must be a pointer")
	}

	// 获取结构体类型
	destType := reflect.TypeOf(dest).Elem()
	if destType.Kind() != reflect.Struct {
		return errors.New("dest must point to a struct")
	}

	// 执行查询
	rows, err := db.Queryx(query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	// 检查是否有结果
	if !rows.Next() {
		return sql.ErrNoRows
	}

	result := make(map[string]interface{})
	if err := rows.MapScan(result); err != nil {
		// 处理错误
		return err
	}

	// 将map结果映射到结构体
	destValue := reflect.ValueOf(dest).Elem()
	for i := 0; i < destValue.NumField(); i++ {
		field := destValue.Field(i)
		if !field.CanSet() {
			continue
		}

		// 获取字段的db tag或字段名
		fieldType := destType.Field(i)
		fieldName := fieldType.Name
		if tag := fieldType.Tag.Get("db"); tag != "" {
			fieldName = tag
		}

		// 从map中获取值并设置到结构体字段
		if value, ok := result[strings.ToLower(fieldName)]; ok {
			val := reflect.ValueOf(value)
			if val.Type().ConvertibleTo(field.Type()) {
				field.Set(val.Convert(field.Type()))
			}
		}
	}

	return nil
}

// GetMultipleRecords 通用多条记录查询方法
// dest: 指向目标结构体数组的指针
// db: 数据库连接
// query: SQL查询语句
// args: 查询参数
func GetMultipleRecords(db *sqlx.DB, dest interface{}, query string, args ...interface{}) error {
	// 验证dest必须是指向切片的指针
	if reflect.ValueOf(dest).Kind() != reflect.Ptr {
		return errors.New("dest must be a pointer")
	}

	// 获取切片类型和元素类型
	sliceValue := reflect.Indirect(reflect.ValueOf(dest))
	if sliceValue.Kind() != reflect.Slice {
		return errors.New("dest must be a slice pointer")
	}
	elemType := sliceValue.Type().Elem()
	if elemType.Kind() == reflect.Ptr {
		elemType = elemType.Elem()
	}
	// 执行查询
	rows, err := db.Queryx(query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()
	// 获取map结果
	result := make(map[string]interface{})
	// 遍历结果集
	for rows.Next() {
		if err := rows.MapScan(result); err != nil {
			return err
		}
		// 创建新的结构体实例
		var elem reflect.Value
		if elemType.Kind() == reflect.Struct {
			elem = reflect.New(elemType).Elem()
		} else {
			elem = reflect.New(elemType)
		}

		// 将map结果映射到结构体
		for i := 0; i < elem.NumField(); i++ {
			field := elem.Field(i)
			if !field.CanSet() {
				continue
			}

			// 获取字段的db tag或字段名
			fieldType := elemType.Field(i)
			fieldName := fieldType.Name
			if tag := fieldType.Tag.Get("db"); tag != "" {
				fieldName = tag
			}

			// 从map中获取值并设置到结构体字段
			if value, ok := result[strings.ToLower(fieldName)]; ok {
				val := reflect.ValueOf(value)
				if val.Type().ConvertibleTo(field.Type()) {
					field.Set(val.Convert(field.Type()))
				}
			}
		}
		// 根据元素类型决定如何添加到切片
		if elemType.Kind() == reflect.Ptr {
			sliceValue.Set(reflect.Append(sliceValue, elem))
		} else {
			sliceValue.Set(reflect.Append(sliceValue, elem.Addr()))
		}
	}

	return nil
}
